package com.sunyard.utils.ftputil;


import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Properties;
import java.util.Vector;

/**
 * SFTP工具类
 *
 * @author 黄志鑫
 * @date 2018/3/29 15:40
 */
public class SFTPUtils {
    /**
     * Description
     */
    private static Logger log = LoggerFactory.getLogger(SFTPUtils.class);

    /**
     * Description
     */
    private String host;//服务器连接ip
    /**
     * Description
     */
    private String username;//用户名
    /**
     * Description
     */
    private String password;//密码
    /**
     * Description
     */
    private int port = 22;//端口号
    /**
     * Description
     */
    private ChannelSftp sftp = null;
    /**
     * Description
     */
    private Session sshSession = null;

    /**
     * Description
     */
    public SFTPUtils() {
    }

    /**
     * 构造函数
     *
     * @param host     主机号
     * @param port     端口号
     * @param username 用户名
     * @param password 密码
     */
    public SFTPUtils(String host, int port, String username, String password) {
        this.host = host;
        this.username = username;
        this.password = password;
        this.port = port;
    }

    /**
     * 构造函数
     *
     * @param host     主机号
     * @param username 用户名
     * @param password 密码
     */
    public SFTPUtils(String host, String username, String password) {
        this.host = host;
        this.username = username;
        this.password = password;
    }


    /**
     * Description
     */
    private static int sftpPort = 22;
    /**
     * Description
     */
    private static Session session = null;
    /**
     * Description
     */
    private static ChannelSftp channel = null;

    /**
     * sftp密钥登陆
     *
     * @param sftpHost     主机号
     * @param port         端口号
     * @param sftpUserName 用户名
     * @param priKeyPath   密码
     * @param timeout      超时时间
     * @return 返回结果
     */
    public ChannelSftp getConnect(String sftpHost, String port, String sftpUserName, String priKeyPath,
                                  String timeout) {
        if (null != port && !"".equals(port)) {
            sftpPort = Integer.parseInt(port);
        }
        JSch jSch = new JSch();

        try {
            jSch.addIdentity(priKeyPath);
            session = jSch.getSession(sftpUserName, sftpHost, sftpPort);
            log.debug("session created");
            if (!(null == timeout || "".equals(timeout))) {
                int sftpTimeout = Integer.parseInt(timeout);
                session.setTimeout(sftpTimeout);
            }
            session.setConfig("StrictHostKeyChecking", "no");
            session.setConfig("UseDNS", "no");
            session.connect();
            log.debug("Opening SFTP Channel...");
            /**
             * 打开SFTP通道
             */
            channel = (ChannelSftp) session.openChannel("sftp");
            /**
             * 建立sftp连接
             */
            channel.connect();
            log.info("sftp 登陆成功");
        } catch (JSchException e) {
            log.error("sftp 连接失败" + e);
        }
        return channel;
    }

    /**
     * 关闭连接
     *
     * @throws Exception 异常
     */
    public static void closeChannel() throws Exception {

        try {
            if (null != channel) {
                channel.disconnect();
            }
            if (null != session) {
                session.disconnect();
            }
        } catch (Exception e) {
            log.error("close sftp error", e);
            throw new Exception("close ftp error..");
        }
    }

    /**
     * 通过SFTP连接服务器
     */
    public void connect() {
        try {
            JSch jsch = new JSch();
            jsch.getSession(username, host, port);
            sshSession = jsch.getSession(username, host, port);
            if (log.isInfoEnabled()) {
                log.info("Session created.");
            }
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            if (log.isInfoEnabled()) {
                log.info("Session connected.");
            }
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            if (log.isInfoEnabled()) {
                log.info("Opening Channel.");
            }
            sftp = (ChannelSftp) channel;
            if (log.isInfoEnabled()) {
                log.info("Connected to " + host + ".");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 连接
     *
     * @param host     主机号
     * @param port     端口号
     * @param username 用户名
     * @param password 密码
     * @return 返回结果
     * @throws JSchException 异常
     */
    public ChannelSftp connect(String host, int port, String username, String password) throws JSchException {
        //1.声明连接Sftp的通道
        ChannelSftp nChannelSftp = null;
        //2.实例化JSch
        JSch nJSch = new JSch();
        //3.获取session
        Session nSShSession = nJSch.getSession(username, host, port);
        log.info("Session创建成功");
        //4.设置密码
        nSShSession.setPassword(password);
        //5.实例化Properties
        Properties nSSHConfig = new Properties();
        //6.设置配置信息
        nSSHConfig.put("StrictHostKeyChecking", "no");
        //7.session中设置配置信息
        nSShSession.setConfig(nSSHConfig);
        //8.session连接
        nSShSession.connect();
        log.info("Session已连接");
        //9.打开sftp通道
        Channel channel = nSShSession.openChannel("sftp");
        //10.开始连接
        channel.connect();
        nChannelSftp = (ChannelSftp) channel;
        log.info("连接到主机" + host + ".");
        return nChannelSftp;
    }

    /**
     * 关闭连接
     */
    public void disconnect() {
        if (this.sftp != null) {
            if (this.sftp.isConnected()) {
                this.sftp.disconnect();
                if (log.isInfoEnabled()) {
                    log.info("sftp is closed already");
                }
            }
        }
        if (this.sshSession != null) {
            if (this.sshSession.isConnected()) {
                this.sshSession.disconnect();
                if (log.isInfoEnabled()) {
                    log.info("sshSession is closed already");
                }
            }
        }
    }

    /**
     * 下载单个文件
     *
     * @param remotePath     远程下载目录(以路径符号结束)
     * @param remoteFileName 下载文件名
     * @param localPath      本地保存目录(以路径符号结束)
     * @param localFileName  保存文件名
     * @return 返回结果
     */
    public boolean downloadFile(String remotePath, String remoteFileName, String localPath, String localFileName) {
        FileOutputStream fieloutput = null;
        try {
            //sftp.cd(remotePath);
            File file = new File(localPath + localFileName);
            mkdirs(localPath + localFileName);
            fieloutput = new FileOutputStream(file);
            sftp.get(remotePath + remoteFileName, fieloutput);
            if (log.isInfoEnabled()) {
                log.info("===DownloadFile:" + remoteFileName + " success from sftp.");
            }
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        } finally {
            if (null != fieloutput) {
                try {
                    fieloutput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 下载单个文件
     *
     * @param channelSftp    sftp通道
     * @param remotePath     远程下载目录(以路径符号结束)
     * @param remoteFileName 下载文件名
     * @param localPath      本地保存目录(以路径符号结束)
     * @param localFileName  保存文件名
     * @return 返回结果
     */
    public boolean downloadFile2(ChannelSftp channelSftp, String remotePath, String remoteFileName, String localPath,
                                 String localFileName) {
        FileOutputStream fieloutput = null;
        try {
            log.info("要下载的远程文件时：" + remotePath + remoteFileName);
            //sftp.cd(remotePath);
            File file = new File(localPath + localFileName);
            mkdirs(localPath + localFileName);
            fieloutput = new FileOutputStream(file);
            /**
             * 下载远程文件
             */
            channelSftp.get(remotePath + remoteFileName, fieloutput);
            if (log.isInfoEnabled()) {
                log.info("===DownloadFile:" + remoteFileName + " success from sftp.");
            }
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != fieloutput) {
                try {
                    fieloutput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 下载
     *
     * @param sourceFileName 源文件名称
     * @return 返回结果
     */
    public byte[] downloadFile(String sourceFileName) {
        byte[] bytes = new byte[0];
        try {
            InputStream inputStream = sftp.get(sourceFileName);
            bytes = toByteArray(inputStream);
            inputStream.close();
        } catch (SftpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * 流转byte数组
     *
     * @param in 输入流
     * @return 返回结果
     * @throws IOException 异常
     */
    public static byte[] toByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }

    /**
     * 上传单个文件
     *
     * @param remotePath     远程保存目录
     * @param remoteFileName 保存文件名
     * @param file           文件
     * @return 返回结果
     */
    public boolean uploadFile(String remotePath, String remoteFileName, File file) {
        FileInputStream in = null;
        try {
            createDir(remotePath);
            //File file = new File(localPath + localFileName);
            in = new FileInputStream(file);
            sftp.setFilenameEncoding("UTF-8");
            sftp.put(in, remoteFileName);
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 批量上传文件
     *
     * @param remotePath 远程保存目录
     * @param localPath  本地上传目录(以路径符号结束)
     * @param del        上传后是否删除本地文件
     * @param type       0:商户补全信息,商户图片
     * @return 返回结果
     */
    public boolean bacthUploadFile(String remotePath, String localPath,
                                   boolean del, String type) {
        try {
            connect();
            File file = new File(localPath);
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                if (files[i].isFile() && "0".equals(type)) {
                    if (files[i].getName().indexOf("jpg") == -1 && files[i].getName().indexOf("tar") == -1) {
                        if (this.uploadFile(remotePath, files[i].getName(), files[i]) && del) {
                            deleteFile(localPath + files[i].getName());
                        }
                    }
                } else {
                    if (files[i].getName().indexOf("txt") == -1 && files[i].getName().indexOf("jpg") == -1) {
                        if (this.uploadFile(remotePath, files[i].getName(), files[i]) && del) {
                            deleteFile(localPath + files[i].getName());
                        }
                    }
                }

            }
            if (log.isInfoEnabled()) {
                log.info("upload file is success:remotePath=" + remotePath
                        + "and localPath=" + localPath + ",file size is "
                        + files.length);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.disconnect();
        }
        return false;

    }

    /**
     * 删除本地文件
     *
     * @param filePath 文件路径
     * @return 返回结果
     */
    public boolean deleteFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            return false;
        }

        if (!file.isFile()) {
            return false;
        }
        boolean rs = file.delete();
        if (rs && log.isInfoEnabled()) {
            log.info("delete file success from local.");
        }
        return rs;
    }

    /**
     * 创建目录
     *
     * @param createpath 创建的路径
     * @return 返回结果
     */
    public boolean createDir(String createpath) {
        try {
            if (isDirExist(createpath)) {
                this.sftp.cd(createpath);
                return true;
            }
            String[] pathArry = createpath.split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArry) {
                if ("".equals(path)) {
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString())) {
                    sftp.cd(filePath.toString());
                } else {
                    //建立目录
                    sftp.mkdir(filePath.toString());
                    //进入并设置为当前目录
                    sftp.cd(filePath.toString());
                }

            }
            this.sftp.cd(createpath);
            return true;
        } catch (SftpException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 创建目录
     *
     * @param path 删除的路径
     * @return 返回结果
     */
    public static boolean deleteDir(String path) {
        try {
            File file = new File(path);
            if (file.isDirectory()) {
                String[] tempList = file.list();
                File temp = null;
                for (int i = 0; i < tempList.length; i++) {
                    temp = new File(path + "\\" + tempList[i]);
                    if (temp.isFile()) {
                        temp.delete();
                    }
                }
                //删除文件夹
                file.delete();
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 判断目录是否存在
     *
     * @param directory 目标目录
     * @return 返回结果
     */
    public boolean isDirExist(String directory) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if ("no such file".equals(e.getMessage().toLowerCase())) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    /**
     * 删除stfp文件
     *
     * @param filePath 文件路径
     */
    public void deleteSFTP(String filePath) {
        try {
            //sftp.cd(directory);
            sftp.rm(filePath);
            if (log.isInfoEnabled()) {
                log.info("delete file success from sftp.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 如果目录不存在就创建目录
     *
     * @param path 目录路径
     */
    public void mkdirs(String path) {
        File f = new File(path);

        String fs = f.getParent();

        f = new File(fs);

        if (!f.exists()) {
            f.mkdirs();
        }
    }

    /**
     * 列出目录下的文件
     *
     * @param directory 要列出的目录
     * @return 返回结果
     * @throws SftpException 异常
     */
    public Vector listFiles(String directory) throws SftpException {
        return sftp.ls(directory);
    }


    /**
     * 罗列文件
     *
     * @param directory 目标目录
     * @param sftp      sftp通道
     * @return 返回结果
     * @throws SftpException 异常
     */
    public Vector listFiles(String directory, ChannelSftp sftp) throws SftpException {
        return sftp.ls(directory);
    }

    /**
     * 获取主机号
     *
     * @return 返回结果
     */
    public String getHost() {
        return host;
    }

    /**
     * 设置主机号
     *
     * @param host 主机号
     */
    public void setHost(String host) {
        this.host = host;
    }

    /**
     * 获取用户名
     *
     * @return 返回结果
     */
    public String getUsername() {
        return username;
    }

    /**
     * 设置用户名
     *
     * @param username 用户名
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * 获取密码
     *
     * @return 返回结果
     */
    public String getPassword() {
        return password;
    }

    /**
     * 设置密码
     *
     * @param password 密码
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * 获取端口号
     *
     * @return 返回结果
     */
    public int getPort() {
        return port;
    }

    /**
     * 设置端口号
     *
     * @param port 端口号
     */
    public void setPort(int port) {
        this.port = port;
    }

    /**
     * 获取通道
     *
     * @return 返回结果
     */
    public ChannelSftp getSftp() {
        return sftp;
    }

    /**
     * 设置通道
     *
     * @param sftp sftp通道
     */
    public void setSftp(ChannelSftp sftp) {
        this.sftp = sftp;
    }


    /**
     * 测试
     */
    //public static void main(String[] args)
    //{
    //SFTPUtils sftp = null;
    ////本地存放地址
    //String localPath = "D:/tomcat5/webapps/ASSESS/DocumentsDir/DocumentTempDir/txtData/";
    ////Sftp下载路径
    //String sftpPath = "/home/assess/sftp/jiesuan_2/2014/";
    //List<String> filePathList = new ArrayList<String>();
    //try
    //{
    //sftp = new SFTPUtils("10.163.201.115", "tdcp", "tdcp");
    //sftp.connect();
    ////下载
    //sftp.batchDownLoadFile(sftpPath, localPath, "ASSESS", ".txt", true);
    //}
    //catch (Exception e)
    //{
    //e.printStackTrace();
    //}
    //finally
    //{
    //sftp.disconnect();
    //}
    //}
    //public static void main(String[] args) {
    //SFTPUtils sftpUtils = new SFTPUtils();
    //sftpUtils.getConnect();
    //}
}



